Bash Tutorial: getopts
The getopts command is a built in shell command for parsing command line arguments. It is better than the getopt alternative for several reasons. It's defined in POSIX and has a single implementation that's native to bash. Using getopts, you don't have to hit an external program or provide options in a specific order for it to work. In this tutorial, we run through the basics of using getopts to parse command line arguments for your bash scripts.
getopts basic example
Let's say you have a basic sample.sh script that takes a single option a:
$ ./sample.sh -a
You can implement this as follows:
#!/bin/bash
while getopts "a" opt; do
case $opt in
a)
echo "argument -a called" >&2
;;
esac
done
The output of this script will be:
>argument -a called
Notice how we use the getopts command within a while loop. This iterates through each option in our option string. In this case, our options string is simply "a".
getopts option with parameter
Let's say you want the option a to accept a parameter:
$ ./sample.sh -a hello
Notice how we are now passing in a parameter hello with the option a. We can implement getopts as follows:
#!/bin/bash
while getopts "a:" opt; do
case $opt in
a)
echo "argument -a called with parameter $OPTARG" >&2
;;
esac
done
The output of this script will be:
argument -a called with parameter hello
Notice the colon in our option string. Any character that is followed by a : indicates that the option takes a parameter.
getopts default errors
What happens if we don't pass a parameter after specifying a: in our option string? The output will be:
./sample.sh: option requires an argument -- a
Bash will throw an error since we specified that the argument a requires a parameter.
For production scripts, you typically want to handle errors yourself. This keeps your code cleaner and gives you more control over the output of your scripts. If you begin the options string with a colon, this enables "silent error mode":
#!/bin/bash
while getopts ":a:" opt; do
case $opt in
a)
echo "argument -a called with parameter $OPTARG" >&2
;;
esac
done
Now when we run the script without a parameter we won't see any error message in the output. This is because we've started the option string with a colon :a:.
getopts handling errors yourself
Even in "silent error mode", you may want to communicate your own message to the user informing them that the command is invalid. You can implement a catch-all for any argument that doesn't match the option string or is missing a parameter:
#!/bin/bash
while getopts ":a:" opt; do
case $opt in
a)
echo "argument -a called with parameter $OPTARG" >&2
;;
*)
echo "invalid command: no parameter included with argument $OPTARG"
;;
esac
done
Now if we don't pass a parameter with the a argument, the output of this script will be:
invalid command: no parameter included with argument a
getopts working with multiple arguments
You can work with any number of arguments in your option string. Let's say you have a script taking two parameters, a and b:
$ ./sample.sh -a hello -b
Notice how the argument a takes a parameter hello while the b argument acts as a flag. We could implement this like so:
#!/bin/bash
while getopts ":a:b" opt; do
case $opt in
a)
echo "argument -a called with parameter $OPTARG" >&2
;;
b)
echo "argument -b called" >&2
;;
*)
echo "invalid command"
;;
esac
done
The output of this script will be:
argument -a called with parameter hello
argument -b called
Notice how our options string includes a colon after argument a but not argument b. This means the that argument a expects a parameter while b does not. Also remember that the options string starts with a colon. This means "silent error mode" is enabled.
If we wanted both a and b to take parameters like:
$ ./sample.sh -a hello -b goodbye
#!/bin/bash
while getopts ":a:b:" opt; do
case $opt in
a)
echo "argument -a called with parameter $OPTARG" >&2
;;
b)
echo "argument -b called with parameter $OPTARG" >&2
;;
*)
echo "invalid command: no parameter included with argument $OPTARG"
;;
esac
done
The output of this script will be:
argument -a called with parameter hello
argument -b called with parameter goodbye
Conclusion
Working with getopts takes some getting used to but is ultimately the preferred way to parse optional arguments in bash. Remember that optargs is typically used within a while loop to iterate through the different options in the string. Whenever a character is followed by a colon, the argument expects a parameter. Whenever an option string starts with a colon, "silent error mode " is enabled. This gives you more control of your script output.